/*
  Name: DeadProxyProtocol.h
  Copyright:
  Author: Carl Chatfield
  Date: 22/01/08 12:38
  Description: Implementation of tibias protocol
*/

#include "DeadProxyApp.h"
#include "DeadProxyProtocol.h"
#include "DeadProxyClient.h"
#include <stdio.h>

Protocol::Protocol(void * ClientPtr)
{
    pClient = ClientPtr;
}

void Protocol::TestMap()
{
    FILE * test;
    test = fopen("testpacket.bin", "rb");
    packet = new PacketBuffer();
    packet->NewBuffer(4290);
    fread(packet->GetBuffer(), 1, 4290, test);
    packet->Skip(18);
    ParseMapDescription(18, 14, 0, 0, 7);
}

void Protocol::ParsePacket(PacketBuffer * pack)
{
    packet = pack;
    
}

bool Protocol::ParseGameMsg()
{
    unsigned char msgId = packet->ReadChar();
    switch (msgId)
    {
        case 0x0A: // Init Player Tibia ID
        {
	        ((Client*)pClient)->Player->SetPlayerId(packet->ReadInt());
            return true;
        }
//        case 0x0B: // GM Actions
//            nm->Trim(32); // unknown
//            return true;
//        case 0x0C: {// The Outcast Character Manager Packets
//            unsigned char tocm = nm->GetU8();
//            switch (tocm) {
//                case 0x01: // enter
//                    newgamemode = GM_CHARMGR;
//                    break;
//                default:
//                    Close();
//            }
//            return true;
//        }
//        case 0x14: // Generic login error message
//            errormsg = nm->GetString();
//            SoundPlay("sounds/error.wav");
//            logonsuccessful = false;
//            return false;
//        case 0x15: {// Messagebox Popup ("for your information")
//            std::string msg = nm->GetString(); // message
//            if (gamemode == GM_GAMEWORLD) ((GM_Gameworld*)game)->MsgBox(msg.c_str(), "For your information");
//            return true;
//        }
//        case 0x16: // Too Many Players login error message
//            errormsg = nm->GetString();
//            {
//                char tmp[255];
//                sprintf(tmp, "\nYou can retry in %d seconds", (unsigned short)nm->GetU8());
//                errormsg = errormsg + tmp;
//            }
//            logonsuccessful = false;
//            return false;
//        case 0x1E: {// Ping Message
//            NetworkMessage nm2;
//            nm2.AddU8(0x1E);
//            if (this->protocolversion >= 770) nm2.XTEAEncrypt(key);
//            nm2.Dump(s);
//            }
//            return true;
//        case 0x28: {// You are dead message
//            nm->ShowContents();
//            console.insert("You've died, mister. Really really badly died.", CONRED);
//            if (gamemode == GM_GAMEWORLD) ((GM_Gameworld*)game)->MsgBox("You have went through the unfortunate process of dying.\nHopefully, you will be able to restore your experience\npoints and resume playing. If you have a high-level\nfriend, don't forget to contact him or her so that\nyou get avenged.\n\nAnd train so that you're not a n00b.", "You're dead");
//            return true;
//        }
        case 0x32: // Something Else, Bug Report
        {
            packet->Skip(3);
            return true;
        }
        case 0x64: // Player Location Setup
        {
            Position pos = packet->ReadPos();
            ((Client*)pClient)->Map->SetPos(pos);
            ParseMapDescription(18, 14, pos.x - 8, pos.y - 6, pos.z);
            return true;
        }
        case 0x65: // Move Player North
        {
            Position p = ((Client*)pClient)->Map->GetPos();
            p.y -= 1;
            ((Client*)pClient)->Map->SetPos(p);
            ParseMapDescription(18, 1, p.x - 8, p.y - 6, p.z);
            return true;
        }
        case 0x66: // Move Player East
        {
            Position p = ((Client*)pClient)->Map->GetPos();
            p.x += 1;
            ((Client*)pClient)->Map->SetPos(p);
            ParseMapDescription(1, 14, p.x + 9, p.y - 6, p.z);
            return true;
        }
        case 0x67: // Move Player South
        {
            Position p = ((Client*)pClient)->Map->GetPos();
            p.y += 1;
            ((Client*)pClient)->Map->SetPos(p);
            ParseMapDescription(18, 1, p.x - 8, p.y + 7, p.z);
            return true;
        }
        case 0x68: // Move Player West
        {
            Position p = ((Client*)pClient)->Map->GetPos();
            p.x -= 1;
            ((Client*)pClient)->Map->SetPos(p);
            ParseMapDescription(1, 14, p.x - 8, p.y - 6, p.z);
            return true;
        }
        case 0x69:  // Tile Update
        {
            Position pos = packet->ReadPos();
            if (packet->ReadShort() > 0xFF00)
            {
            	Tile * T = ((Client*)pClient)->Map->GetTile(pos);
            	((Client*)pClient)->Map->ClearTile(T);
           	    packet->Skip(2);
            } else {
                ParseTileDescription(pos.x, pos.y, pos.z);
            }
            return true;
        }
        case 0x6A:  // Add Item
        {
            Position pos = packet->ReadPos();
            Tile * T = ((Client*)pClient)->Map->GetTile(pos);
            Thing * thing = ParseThingDescription();
            ((Client*)pClient)->Map->AddThing(T, thing);
            return true;
        }
        case 0x6B:  // Replace Item
        {
            Position pos = packet->ReadPos();
            Tile * T = ((Client*)pClient)->Map->GetTile(pos);
            unsigned char StackPos = packet->ReadChar();
            Thing * thing = ParseThingDescription();
            ((Client*)pClient)->Map->ReplaceThing(T, StackPos, thing);
            return true;
        }
        case 0x6C:  // Remove Item
        {
            Position pos = packet->ReadPos();
            Tile * T = ((Client*)pClient)->Map->GetTile(pos);
            unsigned char StackPos = packet->ReadChar();
            ((Client*)pClient)->Map->RemoveThing(T, StackPos);
            return true;
        }
        case 0x6D:  // Move Item
        {
            Position pos = packet->ReadPos();
            Tile * T1 = ((Client*)pClient)->Map->GetTile(pos);
            unsigned char stackpos = packet->ReadChar();
            pos = packet->ReadPos();
            Tile * T2 = ((Client*)pClient)->Map->GetTile(pos);
            ((Client*)pClient)->Map->MoveThing(T1, stackpos, T2);
            //To Do: Add look direction for monsters if i feel like it
            return true;
        }
        case 0x6E: // Container Open
        {
            unsigned char index = packet->ReadChar();
            unsigned short icon = packet->ReadShort();
            char * title = packet->ReadString();
            unsigned char maxSize = packet->ReadChar();
            unsigned char hasParent = packet->ReadChar();
            ((Client*)pClient)->Containers->OpenContainer(index, icon, title, maxSize, hasParent);
            unsigned int itemcount = packet->ReadChar();
            for(int i = 0; i < itemcount; i++)
            {
                ((Client*)pClient)->Containers->InitAddItem(index, ParseThingDescription());
            }
            return true;
        }
        case 0x6F: // Container Close
        {
            unsigned char index = packet->ReadChar();
            ((Client*)pClient)->Containers->CloseContainer(index);
            return true;
        }
        case 0x70: // Add Container Item
        {
            unsigned char index = packet->ReadChar();
            ((Client*)pClient)->Containers->AddItem(index, ParseThingDescription());
            return true;
        }
        case 0x71: // Replace Container Item
        {
            unsigned char index = packet->ReadChar();
            unsigned char slot = packet->ReadChar();
            ((Client*)pClient)->Containers->RepItem(index, slot, ParseThingDescription());
            return true;
        }
        case 0x72: // Remove Container Item
        {
            unsigned char index = packet->ReadChar();
            unsigned char slot = packet->ReadChar();
            ((Client*)pClient)->Containers->RemItem(index, slot);
            return true;
        }
        case 0x78: // Inventory Item
        {
            unsigned int slotid = packet->ReadChar(); // item slot
            switch(slotid)
            {
                case 1:
                    ((Client*)pClient)->Player->SetHeadSlot(ParseThingDescription());
                    break;
                case 2:
                    ((Client*)pClient)->Player->SetNeckSlot(ParseThingDescription());
                    break;
                case 3:
                    ((Client*)pClient)->Player->SetBackSlot(ParseThingDescription());
                    break;
                case 4:
                    ((Client*)pClient)->Player->SetArmorSlot(ParseThingDescription());
                    break;
                case 5:
                    ((Client*)pClient)->Player->SetRightSlot(ParseThingDescription());
                    break;
                case 6:
                    ((Client*)pClient)->Player->SetLeftSlot(ParseThingDescription());
                    break;
                case 7:
                    ((Client*)pClient)->Player->SetLegsSlot(ParseThingDescription());
                    break;
                case 8:
                    ((Client*)pClient)->Player->SetFeetSlot(ParseThingDescription());
                    break;
                case 9:
                    ((Client*)pClient)->Player->SetRingSlot(ParseThingDescription());
                    break;
                case 10:
                    ((Client*)pClient)->Player->SetArrowSlot(ParseThingDescription());
                    break;
            }
            return true;
        }
        case 0x79: // Inventory Empty
        {
            Thing emptything;
            emptything.objectId = 0;
            emptything.data1 = 0;
            emptything.data2 = 0;
            unsigned int slotid = packet->ReadChar(); // item slot
            switch(slotid)
            {
                case 1:
                    ((Client*)pClient)->Player->SetHeadSlot(&emptything);
                    break;
                case 2:
                    ((Client*)pClient)->Player->SetNeckSlot(&emptything);
                    break;
                case 3:
                    ((Client*)pClient)->Player->SetBackSlot(&emptything);
                    break;
                case 4:
                    ((Client*)pClient)->Player->SetArmorSlot(&emptything);
                    break;
                case 5:
                    ((Client*)pClient)->Player->SetRightSlot(&emptything);
                    break;
                case 6:
                    ((Client*)pClient)->Player->SetLeftSlot(&emptything);
                    break;
                case 7:
                    ((Client*)pClient)->Player->SetLegsSlot(&emptything);
                    break;
                case 8:
                    ((Client*)pClient)->Player->SetFeetSlot(&emptything);
                    break;
                case 9:
                    ((Client*)pClient)->Player->SetRingSlot(&emptything);
                    break;
                case 10:
                    ((Client*)pClient)->Player->SetArrowSlot(&emptything);
                    break;
            }
            return true;
        }
        case 0x7D:  // Trade Request
        case 0x7E:  // Trade Ack
        {
            packet->SkipString();
            unsigned int itemcount = packet->ReadChar();
            for(int i = 0; i < itemcount; i++)
            {
                delete ParseThingDescription();
            }
            return true;
        }
        case 0x7F:  // Trade Close
        {
            return true;
        }
        case 0x82:  // World Light
        {
            packet->SkipChar(); // Light Level
            packet->SkipChar(); // Light Color
            return true;
        }
        case 0x83:  // Magic Effect
        {
            packet->Skip(5); //skip the pos
            packet->SkipChar(); //Effect Id
            return true;
        }
//        case 0x84: {// Animated Text
//        	#ifndef USEEFFECTS
//        	position_t pos; // position
//            GetPosition(nm, &pos);
//
//        	nm->GetU8(); // color
//
//        	std::string msg = "Animated text: ";
//        	msg += nm->GetString(); // message
//        	console.insert(msg, CONBLUE);
//        	return true;
//        	#else
//            position_t pos; // position
//            GetPosition(nm, &pos);
//            Tile *t = Map.GetTile(&pos);
//
//            unsigned char color = nm->GetU8(); // color
//            std::string msg = nm->GetString(); // message
//            Effect *e = new Effect(t);
//            e->SetText(msg, color, true);
//            t->Insert(e, true);
//            return true;
//            #endif
//        }
//        case 0x85: {// Distance Shot
//
//
//            #ifndef USEEFFECTS
//            console.insert("Effects disabled (distance shot)\n", CONRED);
//			position_t src; // position
//            GetPosition(nm, &src);
//
//            position_t dst; // position
//            GetPosition(nm, &dst);
//
//            nm->GetU8(); // type of shot
//
//            return true;
//
//            #else
//            Tile *t;
//            Effect *e;
//            unsigned char type;
//
//
//
//            position_t src; // position
//            GetPosition(nm, &src);
//
//            position_t dst; // position
//            GetPosition(nm, &dst);
//
//			DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL, ">=>=>=>=>=> Distance shot effect %d PT1\n", type);
//
//            t = Map.GetTile(&src);
//            type = nm->GetU8(); // mageffect type
//
//			DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL, ">=>=>=>=>=> Distance shot effect %d PT2\n", type);
//
//            e = new Effect(t);
//            DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL, ">=>=>=>=>=> Distance shot effect %d PT3\n", type);
//            e->SetType(type, (void*)1); // anything but NULL for second argument causes it to be a distance shot
//            DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL, ">=>=>=>=>=> Distance shot effect %d PT4\n", type);
//            e->SetDistanceDeltaTarget(dst.x - src.x, dst.y - src.y);
//            DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL, ">=>=>=>=>=> Distance shot effect %d PT5\n", type);
//
//            t->Insert(e, false);
//			DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL, ">=>=>=>=>=> Distance shot effect %d PT .. doh\n", type);
//
//
//            return true;
//            #endif
//        }
//        case 0x86: // Creature Square
//            nm->GetU32(); // around which creature
//            nm->GetU8(); // square color
//            return true;
//        case 0x8C: {// Creature HP
//            Creature *c = GetCreatureByID(nm);
//            if (c)
//                c->SetHP(nm->GetU8()); // health percent
//            else {
//                //console.insert("There was a problem adjusting a creature's health.\n", CONRED);
//                nm->GetU8();
//            }
//            //if (c) printf("Creature %s health adjustment\n", c->GetName().c_str());
//
//            return true;
//        }
        case 0x8D: // Creature Light
        {
            packet->SkipInt(); //creature id
            packet->SkipChar(); //lightradius
            packet->SkipChar(); //lightcolor
            return true;
        }
//        case 0x8E: {// Set Creature Outfit
//        // DONE abstract this through "getcreaturelook" or somethinglikehtat
//            Creature *cr = GetCreatureByID(nm);//creature id
//
//            creaturelook_t crl;
//            ParseCreatureLook(nm, &crl);
//
//            cr->SetType(crl.type, &crl);
//
//            return true;
//        }
//        case 0x8F: // Creature Speed
//            GetCreatureByID(nm);//creature id
//            nm->GetU16(); // speed index
//            return true;
//        case 0x90: {// Creature Skull
//            Creature *cr = GetCreatureByID(nm);
//            cr->SetSkull((skull_t)nm->GetU8());//creature id, skull type
//            return true;
//        }
//        case 0x91: // Creature Shield
//            GetCreatureByID(nm);//creature id
//            nm->GetU8(); // shield type
//            return true;
//        case 0x96: {// Text Window
//            nm->GetU32(); // window id
//            nm->GetU16(); // itemid -- for icon?
//            nm->GetU16(); // max length
//            nm->GetString();
//            if (protocolversion >= 792) { //FIXME (Khaos#2#) Check where exactly this was added
//                nm->GetString(); // unknown
//                nm->GetString();
//            }
//            return true;
//        }
//        case 0x97: // House Window
//            nm->GetU8(); // 0?
//            nm->GetU32(); // creature id
//            nm->GetString(); // dunno, probably house name?
//            return true;
        case 0xA0: // Player Stats
        {
            ParsePlayerStats();
            return true;
        }
        case 0xA1: // Player Skills
        {
            ParsePlayerSkills();
            return true;
        }
        case 0xA2: // Status Icons
        {
            ((Client*)pClient)->Player->SetStatus(packet->ReadShort());
            return true;
        }
//        case 0xA3: // Cancel Attack
//            return true;
        case 0xAA:  // Creature Speak
        {
            Position pos;
            packet->SkipInt(); //No Idea Whatsoever
            char * creaturename = packet->ReadString(); //creatures name
            unsigned short creaturelevel = packet->ReadShort(); //creatures level
            unsigned char msgtype = packet->ReadChar(); //Message Type
//
//            position_t pos(0,0,0);
//            consolecolors_t concol;
//            if (protocolversion > 760) {// i presume?
//                nm->GetU32(); // OT says always 0, perhaps it is NOT!
//            }
//            std::string creaturename = nm->GetString(); // creature name
//            unsigned short creaturelevel=0;
//            if (protocolversion >= 780) {
//                creaturelevel = nm->GetU16(); // player level
//            }
//
//            unsigned char msgtype = nm->GetU8();
//            printf("MSGTYPE: %02x\n", msgtype);
//            switch (msgtype) {
//                case 0x01: // say
//                case 0x02: // whisper
//                case 0x03: // yell
//
//                case 0x10: // monster 1
//                case 0x11: // monster 2
//                    this->GetPosition(nm, &pos);
//                    break;
//                case 0x05: // yellow
//                case 0x0A: // red -- r1 #c gamemaster command
//                case 0x0E: // red -- r2 #d counsellor command ??
//
//                    nm->GetU16(); // channel id
//                    break;
//                case 0x09: // broadcast
//                case 0x04: // private
//                case 0x0B: // private red     @name@text
//                case 0x0C: // orange
//                    break;
//            }
//
//            switch (msgtype) {
//                case 0x01:
//                case 0x02:
//                case 0x03:
//                case 0x05:
//                default:
//                    concol = CONYELLOW;
//                    break;
//                case 0x10:
//                case 0x11:
//                case 0x0C:
//                    concol = CONORANGE;
//                    break;
//                case 0x09:
//                case 0x0A:
//                case 0x0E:
//                    concol = CONRED;
//                    break;
//                case 0x04:
//                    concol = CONLTBLUE;
//            }
//
//            std::string message = nm->GetString(); // message
//
//            console.insert(creaturename + ": " + message, concol);
//
//			#ifdef USEEFFECTS
//            if (pos.x && pos.y && pos.z) {
//                Tile *t = Map.GetTile(&pos);
//                Effect *e = new Effect(t);
//                std::string extratext = "";
//                if (msgtype == 0x01) extratext=" says";
//                if (msgtype == 0x02) extratext=" whispers";
//                if (msgtype == 0x03) extratext=" yells";
//                std::string s = creaturename + extratext + ": " + message;
//                e->SetText(s, 210, false);
//                t->Insert(e, true);
//            }
//            #endif
//
//            return true;
        }


//        case 0xAB: // Channels Dialog
//            {
//                unsigned char chancount = nm->GetU8();
//                for (int i = 0 ; i < chancount ; i++) {
//                    nm->GetU16(); // channel id
//                    nm->GetString(); // channel name
//                }
//            }
//            return true;
//        case 0xAC: // Channel Open
//            nm->GetU16(); // channel id
//            nm->GetString(); // channel name
//            return true;
//        case 0xAD: // Private Open
//            nm->GetString(); // Player name
//            return true;
//        case 0xB2: // Create Private Channel
//            nm->GetU16(); // channel id
//            nm->GetString(); // channel name
//            return true;
//        case 0xB4: {// Text Message
//            std::string y;
//            unsigned char msgclass;
//            consolecolors_t color;
//            msgclass = nm->GetU8(); // msg class
//
//
//            switch (msgclass) {
//                case 0x12: // msgredinfo
//                    color = CONRED;
//                    break;
//                case 0x13: // msgadvance
//                    color = CONGREEN;
//                    break;
//                case 0x14: // msgevent
//                case 0x15: // msgevent (commented out in otserv)
//                    color = CONWHITE;
//                    break;
//                case 0x16: // msginfo
//                    color = CONGREEN;
//                    nm->ShowContents();
//                    break;
//                case 0x17: // msgsmallinfo
//                    color = CONWHITE;
//                    break;
//                case 0x18: // msgbluetext
//                    color = CONBLUE;
//                    break;
//                case 0x19: // msgredtext
//                    color = CONRED;
//                    break;
//                default:
//                    DEBUGPRINT(DEBUGPRINT_LEVEL_OBLIGATORY, DEBUGPRINT_WARNING, "Unknown textmsg class: 0x%02x\n", msgclass);
//                    color = CONWHITE;
//            }
//            console.insert( y = nm->GetString(), color ); // message itself
//            if (y == "Sorry, not possible.") SoundPlay("sounds/bleep.wav");
//            if (y == "You are not invited.") SoundPlay("sounds/bleep2.wav");
//            if (y == "You may not logout during or immediately after a fight!") SoundPlay("sounds/bleep2.wav");
//            return true;
//        }
//        case 0xB5: // Cancel Walk
//			if (player->GetCreature()) {
//				player->GetCreature()->SetDirection((direction_t)nm->GetU8()); // direction
//				player->GetCreature()->CancelMoving();
//				SoundPlay("sounds/bleep.wav");
//			} else {
//				nm->GetU8();
//			}
//            return true;
//        case 0xBE: {// Floor Up
//            DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL,"Move up\n");
//
//            player->SetPos(player->GetPosX()+1, player->GetPosY()+1, player->GetPosZ()-1);
//
//
//            //ParseMapDescription(nm, maxx, maxy, player->GetPosX() - (maxx-1)/2, player->GetPosY() - (maxy-1)/2, player->GetPosZ());
//
//            unsigned int skip=0;
//            if (player->GetPosZ()==7)
//                for (int i = 5 ; i >=0; i--)
//                    ParseFloorDescription(nm, maxx, maxy, player->GetPosX() - (maxx-1)/2, player->GetPosY() - (maxy-1)/2 , i, &skip);
//             else if (player->GetPosZ()>7)
//                ParseFloorDescription(nm, maxx, maxy, player->GetPosX() - (maxx-1)/2, player->GetPosY() - (maxy-1)/2 , player->GetPosZ()-2, &skip);
//
//            player->FindMinZ();
//
//
//
//			player->GetCreature()->ApproveMove();
//            DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL,"End move up\n");
//
//            return true;
//        }
//        case 0xBF: {// Floor Down
//            DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL,"Floor down\n");
//
//
//
//            player->SetPos(player->GetPosX()-1, player->GetPosY()-1, player->GetPosZ()+1);
//
//
//            //ParseMapDescription(nm, maxx, maxy, player->GetPosX() - (maxx-1)/2, player->GetPosY() - (maxy-1)/2, player->GetPosZ());
//            unsigned int skip=0;
//            if (player->GetPosZ()==8) {
//                ParseFloorDescription(nm, maxx, maxy, player->GetPosX() - (maxx-1)/2 , player->GetPosY() - (maxy-1)/2 , player->GetPosZ(), &skip);
//                ParseFloorDescription(nm, maxx, maxy, player->GetPosX() - (maxx-1)/2 , player->GetPosY() - (maxy-1)/2 , player->GetPosZ()+1, &skip);
//                printf("RECEIVING TWO FLOORS\n");
//            }
//            if (player->GetPosZ() >= 8) {
//                ParseFloorDescription(nm, maxx, maxy, player->GetPosX() - (maxx-1)/2 , player->GetPosY() - (maxy-1)/2 , player->GetPosZ()+2, &skip);
//                printf("RECEIVING ONE FLOOR\n");
//            }
//
//
//            player->FindMinZ();
//
//
//
//			player->GetCreature()->ApproveMove();
//            DEBUGPRINT(DEBUGPRINT_LEVEL_DEBUGGING, DEBUGPRINT_NORMAL, "End floor down\n");
//
//            return true;
//        }
//        case 0xC8: {// Outfit List
//            creaturelook_t crl;
//
//            if (this->protocolversion < 790) { // FIXME (Khaos#4#) this is probably incorrect version of protocol where this first appeared. check!
//
//	            Creature *c = GetCreatureByID(nm); // creature id
//
//	            ParseCreatureLook(nm, &crl);
//
//	            nm->GetU8(); // first outfit
//	            nm->GetU8(); // last outfit
//
//            } else {
//                unsigned char countoutfits = nm->GetU8();
//                for (int i = 0; i < countoutfits; i++) {
//                    nm->GetU16(); // look type
//                    nm->GetString(); // outift name
//                    nm->GetU8(); // addons
//                }
//            }
//            return true;
//        }
        case 0xD2: // VIP Add
        {
            unsigned int TibiaId = packet->ReadInt();            // TibiaId
            char * Name = packet->ReadString();         // Name
            unsigned char OnlineChar = packet->ReadChar();
            bool Online;
            if(OnlineChar == 0)
            {
                Online = false;
            } else {
                Online = true;
            }
            ((Client*)pClient)->VIP->AddVIP(TibiaId, Name, Online);
            return true;
        }
        case 0xD3: // VIP Login
        {
            ((Client*)pClient)->VIP->VIPLogin(packet->ReadInt());   //TibiaId
            return true;
        }
        case 0xD4: // VIP Logout
        {
            ((Client*)pClient)->VIP->VIPLogout(packet->ReadInt());   //TibiaId
            return true;
        }
	}
	return false;
}

void Protocol::ParsePlayerSkills() 
{
    ((Client*)pClient)->Player->SetFist(packet->ReadChar());
    ((Client*)pClient)->Player->SetFistPercent(packet->ReadChar());
    ((Client*)pClient)->Player->SetClub(packet->ReadChar());
    ((Client*)pClient)->Player->SetClubPercent(packet->ReadChar());
    ((Client*)pClient)->Player->SetSword(packet->ReadChar());
    ((Client*)pClient)->Player->SetSwordPercent(packet->ReadChar());
    ((Client*)pClient)->Player->SetAxe(packet->ReadChar());
    ((Client*)pClient)->Player->SetAxePercent(packet->ReadChar());
    ((Client*)pClient)->Player->SetDistance(packet->ReadChar());
    ((Client*)pClient)->Player->SetDistancePercent(packet->ReadChar());
    ((Client*)pClient)->Player->SetShielding(packet->ReadChar());
    ((Client*)pClient)->Player->SetShieldingPercent(packet->ReadChar());
    ((Client*)pClient)->Player->SetFishing(packet->ReadChar());
    ((Client*)pClient)->Player->SetFishingPercent(packet->ReadChar());
}

void Protocol::ParsePlayerStats() 
{
    ((Client*)pClient)->Player->SetHp(packet->ReadShort()); // hp
    ((Client*)pClient)->Player->SetMaxHp(packet->ReadShort()); // max hp
    ((Client*)pClient)->Player->SetCap(packet->ReadShort()); // cap
    ((Client*)pClient)->Player->SetExp(packet->ReadInt()); // exp
    ((Client*)pClient)->Player->SetLevel(packet->ReadShort()); // lvl
    ((Client*)pClient)->Player->SetLevelPercent(packet->ReadChar()); // level percent
    ((Client*)pClient)->Player->SetMana(packet->ReadShort()); // mp
    ((Client*)pClient)->Player->SetMaxMana(packet->ReadShort()); // mmp
    ((Client*)pClient)->Player->SetMagicLevel(packet->ReadChar()); // mag lvl
    ((Client*)pClient)->Player->SetMagicLevelPercent(packet->ReadChar()); // maglvl percent
    ((Client*)pClient)->Player->SetSoul(packet->ReadChar()); // soul
    ((Client*)pClient)->Player->SetStamina(packet->ReadShort()); // stamina (minutes)
}

void Protocol::ParseMapDescription(int w, int h, int startx, int starty, int posz)
{
    int startz;
    int endz;
    int stepz;
    unsigned int skip;
    int * z = new int;                                          //I think this is a bug with gcc, allocate it onto the heap or else it will be overwritten
    skip = 0;
    if(posz > 7)                                                //if we are underground
    {
        startz = posz - 2;                                      //we see 2 floors above us
        endz = posz + 2;                                        //and two floors below (no floor 15)
        if(endz > 14)
        {
            endz = 14;
        }
        stepz = 1;                                              //move down
    } else {
        startz = 7;                                             //Start from the surface level
        endz = 4;                                               //Always finish at the top
        stepz = -1;                                             //Move from ground up
    }
    for(*z = startz; *z != endz + stepz; *z += stepz)
    {
        ParseFloorDescription(w, h, startx, starty, *z, &skip);
    }
    delete z;
}

void Protocol::ParseFloorDescription(int w, int h, int startx, int starty, int z, unsigned int * skip)
{
    int x = startx;
    int y = starty;
    while(x < startx + w)
    {
        y = starty;
        while(y < starty + h)
        {
            if(!*skip)                                      //if skip does not equal 0, then we read a tile
            {
                if(packet->PeekShort() >= 0xFF00)
                {
                    *skip = packet->ReadShort() & 0xFF;      //Read the lower byte to skip
                } else {
                    ParseTileDescription(x, y, z);
                    y++;
                }
            } else {
                *skip = *skip - 1;                                    //Decrement skip and move on
                y++;
            }
        }
        x++;
    }
}

void Protocol::ParseTileDescription(int x, int y, int z) {

    Position p;
    p.x = x;
    p.y = y;
    p.z = z;
    Tile * T = ((Client*)pClient)->Map->GetTile(p);
    ((Client*)pClient)->Map->ClearTile(T);
    while(true)
    {
        if(packet->PeekShort() >= 0xFF00)
        {
            return;
        }
        ((Client*)pClient)->Map->AddThing(T, ParseThingDescription());
    }
}

Thing * Protocol::ParseThingDescription() {
    unsigned int type = packet->ReadShort();
    Thing * thing = new Thing;
    unsigned long creatureid;
    unsigned short extendedlook=0;
    switch (type) {
        case 0x0061: // new creature
        case 0x0062: {// known creature
            if (type == 0x0061) { // new creature
            	packet->SkipInt();//Remove id
            	packet->SkipInt();//Creature id
            	packet->SkipString();//Creature name
            }
            if (type == 0x0062) {
                packet->SkipInt();//Creature Id
            }
            unsigned char hp = packet->ReadChar(); // health percent
            unsigned char dir = packet->ReadChar();
            unsigned char looktype = packet->ReadChar();
            if(looktype == 0)
            {
                packet->Skip(12); //Item id
            } else {
                packet->Skip(12); //Details
            }
            break;
        }
        case 0x0063: {// creature that has only direction altered
            packet->SkipInt();
            packet->SkipChar();
            break;
        }
        default: {// regular item
            thing->objectId = type;
            DatReader::ThingData * typeinfo = &app->DataReader->ThingInfo[type - 100];
            if(typeinfo->ThingFlags & (DatReader::IsStackable | DatReader::IsRune))
            {
                packet->Skip(1);
            }
            if(typeinfo->ThingFlags & (DatReader::IsSplash | DatReader::IsFluidContainer))
            {
                packet->Skip(1);
            }
            thing->data1 = 0;
            thing->data2 = 0;
        }
    }
    return thing;
}


